<?php

namespace falcon5\inc\Infrastructure\Services;

use falcon5\inc\Base\WPOption;
use falcon5\inc\Exceptions\RemoteServiceException;
use falcon5\inc\Helpers\FileCacheHelper;
use falcon5\inc\Infrastructure\Models\CacheModel;
use hollisho\helpers\ArrayHelper;
use falcon5\inc\Exceptions\InvalidArgumentException;
use lucatume\DI52\ContainerException;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;

/**
 * Class CacheService
 * @package falcon5\inc\Infrastructure\Services
 */
class CacheService
{

    public function getFilename($path, $lang, $protocol)
    {
        return sprintf("%s#%s#%s", md5($path), $lang, $protocol);
    }

    /**
     * @param string $url
     * @param string $lang
     * @param string $fileName
     * @param int $pageId
     * @return Model
     */
    public function saveCache(string $url, string $lang, string $fileName, int $pageId)
    {
        $where = [
            'url' => $url,
            'lang' => $lang,
            'filename' => $fileName,
        ];
        return CacheModel::query()->updateOrCreate($where, array_merge($where, [
            'page_id' => $pageId
        ]));
    }


    /**
     * @param string $fileName
     * @return Builder|Model|object|null
     */
    public function getCacheByFilename(string $fileName)
    {
        return CacheModel::query()->where('filename', $fileName)->first();
    }

    /**
     * 根据页面id删除缓存
     * @param int $pageId
     * @param string $lang
     * @return bool
     */
    public function delCacheByPageId(int $pageId, string $lang)
    {
        $model = CacheModel::query()->where([
            'page_id' => $pageId,
            'lang' => $lang
        ])->first();
        return $model && $this->delCacheByFilename($model->filename);
    }


    /**
     * 根据文件名删除缓存
     * @param string $fileName
     * @return mixed
     */
    public function delCacheByFilename(string $fileName)
    {
        CacheModel::query()->where('filename', $fileName)->delete();
        return FileCacheHelper::del($fileName);
    }

    /**
     * remove all cache
     * @return void
     */
    public function delAllCache()
    {
        falcon5_cache_dir_is_writable() && FileCacheHelper::delAll();
        return CacheModel::query()->delete();
    }


    /**
     * @param string $keyword
     * @param string $lang
     * @param int $page
     * @param int $pageSize
     * @return array
     * @throws RemoteServiceException
     * @throws InvalidArgumentException
     * @throws ContainerException|\hollisho\helpers\InvalidArgumentException
     */
    public function fetchList(string $keyword, string $lang, int $page = 1, int $pageSize = 10)
    {
        $query = CacheModel::query()
            ->select([
                'id',
                'url',
                'filename',
                'page_id',
                'is_locked',
                'created_at',
                'updated_at',
            ])
            ->selectRaw("GROUP_CONCAT(lang) as lang");

        if ($keyword) {
            $query->where('url', 'like', '%' . $keyword . '%');
        }

        if ($lang) {
            $query->where('lang', $lang);
        }

        $query = $query->groupBy('url');

        $countQuery = clone $query;
        $list = collect($query->forPage($page, $pageSize)->orderBy('id', 'desc')->get())->toArray();
        if ($list) {
            // $pageIds = ArrayHelper::getColumn($list, 'page_id');

            // $pageStatisticsList = [];
            // if ($pageIds) {
            //     $pageIds = implode(',', $pageIds);
            //     /** @var Falcon5Service $falcon5Service */
            //     $falcon5Service = falcon5_app(Falcon5Service::class);
            //     $result = $falcon5Service->getPageStatisticsList($pageIds, 1, 100);
            //     $pageStatisticsList = ArrayHelper::getValue($result, 'data.list');
            //     $pageStatisticsList = $pageStatisticsList ? ArrayHelper::index($pageStatisticsList, 'id') : [];
            // }

            /** @var WPOption $options */
            $options = falcon5_app(WPOption::class);
            foreach ($list as &$item) {
                $item['original_lang'] = $options->getOriginalLanguage();
                $item['original_lang_name'] = ArrayHelper::getValue(falcon5_support_languages(), $item['original_lang'], '');
                $item['lang'] = $item['lang'] ? $this->fetchLangMap(explode(',', $item['lang'])) : [];
                //$item['characters'] = ArrayHelper::getValue($pageStatisticsList, $item['page_id'] . '.characters', 0);
                $item['created_at'] = date('c', $item['created_at']);
                $item['updated_at'] = date('c', $item['updated_at']);
                $item['is_locked'] = intval($item['is_locked']);
            }
        }
        $count = CacheModel::query()->fromSub($countQuery, 'cnt')->count();
        return [
            'list' => $list,
            'total' => $count,
            'page' => $page,
            'page_size' => $pageSize,
        ];
    }

    /**
     * @param array $languages
     * @return array
     * @throws \hollisho\helpers\InvalidArgumentException
     */
    private function fetchLangMap(array $languages): array
    {
        $map = [];
        if  ($languages) foreach ($languages as $lang) {
            $map[] = [
                'code' => $lang,
                'name' => ArrayHelper::getValue(falcon5_support_languages(), $lang, ''),
            ];
        }

        return $map;
    }


    /**
     * lock page cache
     * @param int $cacheId
     * @return int
     */
    public function lockPage(int $cacheId): int
    {
        return CacheModel::query()->where('id', $cacheId)->update([
            'is_locked' => 1
        ]);
    }

    /**
     * unlock page cache
     * @param int $cacheId
     * @return int
     */
    public function unlockPage(int $cacheId): int
    {
        
        return CacheModel::query()->where('id', $cacheId)->update([
            'is_locked' => 0
        ]);
    }
}